home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / misc / pdflib / afmparse.c next >
C/C++ Source or Header  |  1999-01-01  |  46KB  |  1,344 lines

  1. /*
  2.  * Copyright (C) 1988, 1989, 1990, 1991 by Adobe Systems Incorporated. 
  3.  * All rights reserved.
  4.  */
  5.  
  6. /* parseAFM.c
  7.  * 
  8.  * This file is used in conjuction with the parseAFM.h header file.
  9.  * This file contains several procedures that are used to parse AFM
  10.  * files. It is intended to work with an application program that needs
  11.  * font metric information. The program can be used as is by making a
  12.  * procedure call to "parseFile" (passing in the expected parameters)
  13.  * and having it fill in a data structure with the data from the 
  14.  * AFM file, or an application developer may wish to customize this
  15.  * code.
  16.  *
  17.  * There is also a file, parseAFMclient.c, that is a sample application
  18.  * showing how to call the "parseFile" procedure and how to use the data
  19.  * after "parseFile" has returned.
  20.  *
  21.  * Please read the comments in parseAFM.h and parseAFMclient.c.
  22.  *
  23.  * History:
  24.  *    original: DSM  Thu Oct 20 17:39:59 PDT 1988
  25.  *  modified: DSM  Mon Jul  3 14:17:50 PDT 1989
  26.  *    - added 'storageProblem' return code
  27.  *      - fixed bug of not allocating extra byte for string duplication
  28.  *    - fixed typos
  29.  *  modified: DSM  Tue Apr  3 11:18:34 PDT 1990
  30.  *    - added free(ident) at end of parseFile routine
  31.  *  modified: DSM  Tue Jun 19 10:16:29 PDT 1990
  32.  *    - changed (width == 250) to (width = 250) in initializeArray
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <errno.h>
  37. #include <string.h>
  38. #include <math.h>
  39. #ifndef ORIG
  40. #include <stdlib.h>        /* for atof(), atoi() */
  41. #endif
  42.  
  43. #ifdef DOS
  44. #include <stdlib.h>
  45. #endif
  46.  
  47. #include "afmparse.h"
  48.  
  49. #ifdef ORIG
  50. #ifndef DOS
  51. int fgetc(...);
  52. int ungetc(...);
  53. int atoi(...);
  54. int fseek(...);
  55. #endif
  56. #endif
  57.  
  58. #define lineterm EOL    /* line terminating character */
  59.  
  60. #define CR    '\r'    /* Carriage Return */
  61. #define NL    '\n'    /* Newline */
  62. #define DOSEOF  0x1A    /* MS-DOS Dateiende */
  63.  
  64. #define normalEOF 1    /* return code from parsing routines used only */
  65.             /* in this module */
  66. #define Space "space"   /* used in string comparison to look for the width */
  67.             /* of the space character to init the widths array */
  68. #define False "false"   /* used in string comparison to check the value of */
  69.             /* boolean keys (e.g. IsFixedPitch)  */
  70.  
  71. #define MATCH(A,B)        (strncmp((A),(B), MAX_NAME) == 0)
  72.  
  73.  
  74.  
  75. /*************************** GLOBALS ***********************/
  76.  
  77. static char *ident = NULL; /* storage buffer for keywords */
  78.  
  79.  
  80. /* "shorts" for fast case statement 
  81.  * The values of each of these enumerated items correspond to an entry in the
  82.  * table of strings defined below. Therefore, if you add a new string as 
  83.  * new keyword into the keyStrings table, you must also add a corresponding
  84.  * parseKey AND it MUST be in the same position!
  85.  *
  86.  * IMPORTANT: since the sorting algorithm is a binary search, the strings of
  87.  * keywords must be placed in lexicographical order, below. [Therefore, the 
  88.  * enumerated items are not necessarily in lexicographical order, depending 
  89.  * on the name chosen. BUT, they must be placed in the same position as the 
  90.  * corresponding key string.] The NOPE shall remain in the last position, 
  91.  * since it does not correspond to any key string, and it is used in the 
  92.  * "recognize" procedure to calculate how many possible keys there are.
  93.  */
  94.  
  95. enum parseKey {
  96.   ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT, 
  97.   DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, 
  98.   ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN, 
  99.   FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH, 
  100.   ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME, 
  101.   NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, 
  102.   STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS, 
  103.   STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION, 
  104.   UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
  105.   NOPE };
  106.  
  107. /* keywords for the system:  
  108.  * This a table of all of the current strings that are vaild AFM keys.
  109.  * Each entry can be referenced by the appropriate parseKey value (an
  110.  * enumerated data type defined above). If you add a new keyword here, 
  111.  * a corresponding parseKey MUST be added to the enumerated data type
  112.  * defined above, AND it MUST be added in the same position as the 
  113.  * string is in this table.
  114.  *
  115.  * IMPORTANT: since the sorting algorithm is a binary search, the keywords
  116.  * must be placed in lexicographical order. And, NULL should remain at the
  117.  * end.
  118.  */
  119.  
  120. static char *keyStrings[] = {
  121.   "Ascender", "B", "C", "CC", "CapHeight", "Comment",
  122.   "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites", 
  123.   "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern", 
  124.   "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch", 
  125.   "ItalicAngle", "KP", "KPX", "L", "N", 
  126.   "Notice", "PCC", "StartCharMetrics", "StartComposites", 
  127.   "StartFontMetrics", "StartKernData", "StartKernPairs", 
  128.   "StartTrackKern", "StdHW", "StdVW", "TrackKern", "UnderlinePosition", 
  129.   "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
  130.   NULL };
  131.   
  132. /*************************** PARSING ROUTINES **************/ 
  133.   
  134. /*************************** token *************************/
  135.  
  136. /*  A "AFM File Conventions" tokenizer. That means that it will
  137.  *  return the next token delimited by white space.  See also
  138.  *  the `linetoken' routine, which does a similar thing but 
  139.  *  reads all tokens until the next end-of-line.
  140.  */
  141.  
  142. static char *token(FILE *fp)
  143. {
  144.     int ch, idx;
  145.  
  146.     /* skip over white space */
  147.     /* thomas 25.1.94: Anpassung an MS-DOS-Konventionen
  148.     while ((ch = fgetc(fp)) == ' ' || ch == lineterm || 
  149.             ch == ',' || ch == '\t' || ch == ';');
  150.     */
  151.     while ((ch = fgetc(fp)) == ' ' || ch == CR || ch == NL || ch == DOSEOF ||
  152.             ch == ',' || ch == '\t' || ch == ';');
  153.     
  154.     idx = 0;
  155.     /* thomas 25.1.94: Anpassung an MS-DOS-Konventionen
  156.     while (ch != EOF && ch != ' ' && ch != lineterm 
  157.            && ch != '\t' && ch != ':' && ch != ';') 
  158.     */
  159.     while (ch != EOF && ch != ' ' && ch != CR && ch != NL && ch != DOSEOF
  160.            && ch != '\t' && ch != ':' && ch != ';') 
  161.     {
  162.         ident[idx++] = ch;
  163.         ch = fgetc(fp);
  164.     } /* while */
  165.  
  166.     if (ch == EOF && idx < 1) return ((char *)NULL);
  167.     if (idx >= 1 && ch != ':' ) ungetc(ch, fp);
  168.     if (idx < 1 ) ident[idx++] = ch;    /* single-character token */
  169.     ident[idx] = 0;
  170.     
  171.     return(ident);    /* returns pointer to the token */
  172.  
  173. } /* token */
  174.  
  175.  
  176. /*************************** linetoken *************************/
  177.  
  178. /*  "linetoken" will get read all tokens until the EOL character from
  179.  *  the given fp.  This is used to get any arguments that can be
  180.  *  more than one word (like Comment lines and FullName).
  181.  */
  182.  
  183. static char *linetoken(FILE *fp)
  184. {
  185.     int ch, idx;
  186.  
  187.     while ((ch = fgetc(fp)) == ' ' || ch == '\t' ); 
  188.     
  189.     idx = 0;
  190.     /*
  191.     while (ch != EOF && ch != lineterm) 
  192.     */
  193.     while (ch != EOF && ch != CR && ch != NL && ch != DOSEOF)
  194.     {
  195.         ident[idx++] = ch;
  196.         ch = fgetc(fp);
  197.     } /* while */
  198.     
  199.     ungetc(ch, fp);
  200.     ident[idx] = 0;
  201.  
  202.     return(ident);    /* returns pointer to the token */
  203.  
  204. } /* linetoken */
  205.  
  206.  
  207. /*************************** recognize *************************/
  208.  
  209. /*  This function tries to match a string to a known list of
  210.  *  valid AFM entries (check the keyStrings array above). 
  211.  *  "ident" contains everything from white space through the
  212.  *  next space, tab, or ":" character.
  213.  *
  214.  *  The algorithm is a standard Knuth binary search.
  215.  */
  216.  
  217. static enum parseKey recognize(char *ident)
  218. {
  219.     int lower = 0, upper = (int) NOPE, midpoint, cmpvalue;
  220.     BooL found = FALSE;
  221.  
  222.     while ((upper >= lower) && !found)
  223.     {
  224.         midpoint = (lower + upper)/2;
  225.         if (keyStrings[midpoint] == NULL) break;
  226.         cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME);
  227.         if (cmpvalue == 0) found = TRUE;
  228.         else if (cmpvalue < 0) upper = midpoint - 1;
  229.         else lower = midpoint + 1;
  230.     } /* while */
  231.  
  232.     if (found) return (enum parseKey) midpoint;
  233.     else return NOPE;
  234.     
  235. } /* recognize */
  236.  
  237.  
  238. /************************* parseGlobals *****************************/
  239.  
  240. /*  This function is called by "parseFile". It will parse the AFM File
  241.  *  up to the "StartCharMetrics" keyword, which essentially marks the
  242.  *  end of the Global Font Information and the beginning of the character
  243.  *  metrics information. 
  244.  *
  245.  *  If the caller of "parseFile" specified that it wanted the Global
  246.  *  Font Information (as defined by the "AFM File Specification"
  247.  *  document), then that information will be stored in the returned 
  248.  *  data structure.
  249.  *
  250.  *  Any Global Font Information entries that are not found in a 
  251.  *  given file, will have the usual default initialization value
  252.  *  for its type (i.e. entries of type int will be 0, etc).
  253.  *
  254.  *  This function returns an error code specifying whether there was 
  255.  *  a premature EOF or a parsing error. This return value is used by 
  256.  *  parseFile to determine if there is more file to parse.
  257.  */
  258.  
  259. static BooL parseGlobals(FILE *fp, GlobalFontInfo *gfi)
  260. {  
  261.     BooL cont = TRUE, save = (gfi != NULL);
  262.     int error = ok;
  263.     register char *keyword;
  264.     
  265.     /* added by tm Oct. 7. 1997 */
  266.     /* fill in some reasonable default values in global font info in 
  267.      * case they're missing from the AFM file.
  268.      */
  269.     gfi->ascender    = 800;
  270.     gfi->descender    = -200;
  271.     gfi->capHeight    = 700;
  272.     gfi->isFixedPitch    = TRUE;
  273.     gfi->italicAngle    = 0;
  274.     gfi->fontBBox.llx    = -200;
  275.     gfi->fontBBox.lly    = -200;
  276.     gfi->fontBBox.urx    = 1000;
  277.     gfi->fontBBox.ury    = 900;
  278.     gfi->StdHW        = 0;
  279.     gfi->StdVW        = 0;        /* heuristic applies in p_font.c! */
  280.     gfi->underlinePosition    = -100;
  281.     gfi->underlineThickness    = 50;
  282.  
  283.     gfi->weight        = NULL;
  284.     gfi->encodingScheme = NULL;
  285.  
  286.  
  287.     /* end new stuff */
  288.     while (cont)
  289.     {
  290.         keyword = token(fp);
  291.         
  292.         if (keyword == NULL)
  293.           /* Have reached an early and unexpected EOF. */
  294.           /* Set flag and stop parsing */
  295.         {
  296.             error = earlyEOF;
  297.             break;   /* get out of loop */
  298.         }
  299.         if (!save)    
  300.           /* get tokens until the end of the Global Font info section */
  301.           /* without saving any of the data */
  302.             switch (recognize(keyword))  
  303.             {                
  304.                 case STARTCHARMETRICS:
  305.                     cont = FALSE;
  306.                     break;
  307.                 case ENDFONTMETRICS:    
  308.                     cont = FALSE;
  309.                     error = normalEOF;
  310.                     break;
  311.                 default:
  312.                     break;
  313.             } /* switch */
  314.         else {
  315.           /* otherwise parse entire global font info section, */
  316.           /* saving the data */
  317.             switch(recognize(keyword))
  318.             {
  319.                 case STARTFONTMETRICS:
  320.                     keyword = token(fp);
  321.                     gfi->afmVersion = (char *) malloc(strlen(keyword) + 1);
  322.                     strcpy(gfi->afmVersion, keyword);
  323.                     break;
  324.                 case COMMENT:
  325.                     keyword = linetoken(fp);
  326.                     break;
  327.                 case FONTNAME:
  328.                     keyword = token(fp);
  329.                     gfi->fontName = (char *) malloc(strlen(keyword) + 1);
  330.                     strcpy(gfi->fontName, keyword);
  331.                     break;
  332.                 case ENCODINGSCHEME:
  333.                     keyword = token(fp);
  334.                     gfi->encodingScheme = (char *) malloc(strlen(keyword) + 1);
  335.                     strcpy(gfi->encodingScheme, keyword);
  336.                     break; 
  337.                 case FULLNAME:
  338.                     keyword = linetoken(fp);
  339.                     gfi->fullName = (char *) malloc(strlen(keyword) + 1);
  340.                     strcpy(gfi->fullName, keyword);
  341.                     break; 
  342.                 case FAMILYNAME:           
  343.                    keyword = linetoken(fp);
  344.                     gfi->familyName = (char *) malloc(strlen(keyword) + 1);
  345.                     strcpy(gfi->familyName, keyword);
  346.                     break; 
  347.                 case WEIGHT:
  348.                     keyword = token(fp);
  349.                     gfi->weight = (char *) malloc(strlen(keyword) + 1);
  350.                     strcpy(gfi->weight, keyword);
  351.                     break;
  352.                 case ITALICANGLE:
  353.                     keyword = token(fp);
  354.                     gfi->italicAngle = atof(keyword);
  355.                     if (errno == ERANGE) error = parseError;
  356.                     break;
  357.                 case ISFIXEDPITCH:
  358.                     keyword = token(fp);
  359.                     if (MATCH(keyword, False))
  360.                         gfi->isFixedPitch = 0;
  361.                     else 
  362.                         gfi->isFixedPitch = 1;
  363.                     break; 
  364.                 case UNDERLINEPOSITION:
  365.                     keyword = token(fp);
  366.                     gfi->underlinePosition = atoi(keyword);
  367.                     break; 
  368.                 case UNDERLINETHICKNESS:
  369.                     keyword = token(fp);
  370.                     gfi->underlineThickness = atoi(keyword);
  371.                     break;
  372.                 case VERSION:
  373.                     keyword = token(fp);
  374.                     gfi->version = (char *) malloc(strlen(keyword) + 1);
  375.                     strcpy(gfi->version, keyword);
  376.                     break; 
  377.                 case NOTICE:
  378.                     keyword = linetoken(fp);
  379.                     gfi->notice = (char *) malloc(strlen(keyword) + 1);
  380.                     strcpy(gfi->notice, keyword);
  381.                     break; 
  382.                 case FONTBBOX:
  383.                     keyword = token(fp);
  384.                     gfi->fontBBox.llx = atoi(keyword);
  385.                     keyword = token(fp);
  386.                     gfi->fontBBox.lly = atoi(keyword);
  387.                     keyword = token(fp);
  388.                     gfi->fontBBox.urx = atoi(keyword);
  389.                     keyword = token(fp);
  390.                     gfi->fontBBox.ury = atoi(keyword);
  391.                     break;
  392.                 case CAPHEIGHT:
  393.                     keyword = token(fp);
  394.                     gfi->capHeight = atoi(keyword);
  395.                     break;
  396.                 case XHEIGHT:
  397.                     keyword = token(fp);
  398.                     gfi->xHeight = atoi(keyword);
  399.                     break;
  400.         /* added by tm Oct. 7. 97 */
  401.         case STDHW:
  402.                     keyword = token(fp);
  403.                     gfi->StdHW = atoi(keyword);
  404.             break;
  405.         case STDVW:
  406.                     keyword = token(fp);
  407.                     gfi->StdVW = atoi(keyword);
  408.             break;
  409.         /* end new stuff */
  410.                 case DESCENDER:
  411.                     keyword = token(fp);
  412.                     gfi->descender = atoi(keyword);
  413.                     break;
  414.                 case ASCENDER:
  415.                     keyword = token(fp);
  416.                     gfi->ascender = atoi(keyword);
  417.                     break;
  418.                 case STARTCHARMETRICS:
  419.                     cont = FALSE;
  420.                     break;
  421.                 case ENDFONTMETRICS:
  422.                     cont = FALSE;
  423.                     error = normalEOF;
  424.                     break;
  425.                 case NOPE:
  426.                 default:
  427.                     error = parseError;
  428.                     break;
  429.             } /* switch */
  430.     }
  431.     } /* while */
  432.     
  433.     return(error);
  434.     
  435. } /* parseGlobals */    
  436.  
  437.  
  438.  
  439. #ifdef ORIG
  440. /************************* initializeArray ************************/
  441.  
  442. /*  Unmapped character codes are (at Adobe Systems) assigned the
  443.  *  width of the space character (if one exists) else they get the
  444.  *  value of 250 ems. This function initializes all entries in the
  445.  *  char widths array to have this value. Then any mapped character 
  446.  *  codes will be replaced with the width of the appropriate character 
  447.  *  when parsing the character metric section.
  448.  
  449.  *  This function parses the Character Metrics Section looking
  450.  *  for a space character (by comparing character names). If found,
  451.  *  the width of the space character will be used to initialize the
  452.  *  values in the array of character widths. 
  453.  *
  454.  *  Before returning, the position of the read/write pointer of the
  455.  *  file is reset to be where it was upon entering this function.
  456.  */
  457.  
  458. int initializeArray(FILE *fp, int *cwi)
  459. {  
  460.     BooL cont = TRUE, found = FALSE;
  461.     long opos = ftell(fp);
  462.     int code = 0, width = 0, i = 0, error = 0;
  463.     register char *keyword;
  464.   
  465.     while (cont)
  466.     {
  467.         keyword = token(fp);
  468.         if (keyword == NULL)
  469.         {
  470.             error = earlyEOF;
  471.             break; /* get out of loop */
  472.         }
  473.         switch(recognize(keyword))
  474.         {
  475.             case COMMENT:
  476.                 keyword = linetoken(fp);
  477.                 break;
  478.             case CODE:
  479.                 code = atoi(token(fp));
  480.                 break;
  481.             case XWIDTH:
  482.                 width = atoi(token(fp));
  483.                 break;
  484.             case CHARNAME: 
  485.                 keyword = token(fp);
  486.                 if (MATCH(keyword, Space))
  487.                 {    
  488.                     cont = FALSE;
  489.                     found = TRUE;
  490.                 } 
  491.                 break;            
  492.             case ENDCHARMETRICS:
  493.                 cont = FALSE;
  494.                 break; 
  495.             case ENDFONTMETRICS:
  496.                 cont = FALSE;
  497.                 error = normalEOF;
  498.                 break;
  499.             case NOPE:
  500.             default: 
  501.                 error = parseError;
  502.                 break;
  503.         } /* switch */
  504.     } /* while */
  505.     
  506.     if (!found)
  507.         width = 250;
  508.     
  509.     for (i = 0; i < 256; ++i)
  510.         cwi[i] = width;
  511.     
  512.     fseek(fp, opos, 0);
  513.     
  514.     return(error);
  515.         
  516. } /* initializeArray */    
  517. #endif
  518.  
  519.  
  520. /************************* parseCharWidths **************************/
  521.  
  522. /*  This function is called by "parseFile". It will parse the AFM File
  523.  *  up to the "EndCharMetrics" keyword. It will save the character 
  524.  *  width info (as opposed to all of the character metric information)
  525.  *  if requested by the caller of parseFile. Otherwise, it will just
  526.  *  parse through the section without saving any information.
  527.  *
  528.  *  If data is to be saved, parseCharWidths is passed in a pointer 
  529.  *  to an array of widths that has already been initialized by the
  530.  *  standard value for unmapped character codes. This function parses
  531.  *  the Character Metrics section only storing the width information
  532.  *  for the encoded characters into the array using the character code
  533.  *  as the index into that array.
  534.  *
  535.  *  This function returns an error code specifying whether there was 
  536.  *  a premature EOF or a parsing error. This return value is used by 
  537.  *  parseFile to determine if there is more file to parse.
  538.  */
  539.  
  540. static int parseCharWidths(FILE *fp, int *cwi)
  541. {  
  542.     BooL cont = TRUE, save = (cwi != NULL);
  543.     int pos = 0, error = ok;
  544.     register char *keyword;
  545.     
  546.     while (cont)
  547.     {
  548.         keyword = token(fp);
  549.           /* Have reached an early and unexpected EOF. */
  550.           /* Set flag and stop parsing */
  551.         if (keyword == NULL)
  552.         {
  553.             error = earlyEOF;
  554.             break; /* get out of loop */
  555.         }
  556.         if (!save)    
  557.           /* get tokens until the end of the Char Metrics section without */
  558.           /* saving any of the data*/
  559.             switch (recognize(keyword))  
  560.             {                
  561.                 case ENDCHARMETRICS:
  562.                     cont = FALSE;
  563.                     break; 
  564.                 case ENDFONTMETRICS:
  565.                     cont = FALSE;
  566.                     error = normalEOF;
  567.                     break;
  568.                 default: 
  569.                     break;
  570.             } /* switch */
  571.         else
  572.           /* otherwise parse entire char metrics section, saving */
  573.           /* only the char x-width info */
  574.             switch(recognize(keyword))
  575.             {
  576.                 case COMMENT:
  577.                     keyword = linetoken(fp);
  578.                     break;
  579.                 case CODE:
  580.                     keyword = token(fp);
  581.                     pos = atoi(keyword);
  582.                     break;
  583.                 case XYWIDTH:
  584.                 /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
  585.                     keyword = token(fp); keyword = token(fp); /* eat values */
  586.                     error = parseError;
  587.                     break;
  588.                 case XWIDTH:
  589.                     keyword = token(fp);
  590.                     if (pos >= 0) /* ignore unmapped chars */
  591.                         cwi[pos] = atoi(keyword);
  592.                     break;
  593.                 case ENDCHARMETRICS:
  594.                     cont = FALSE;
  595.                     break; 
  596.                 case ENDFONTMETRICS:
  597.                     cont = FALSE;
  598.                     error = normalEOF;
  599.                     break;
  600.                 case CHARNAME:    /* eat values (so doesn't cause parseError) */
  601.                     keyword = token(fp); 
  602.                     break;
  603.                 case CHARBBOX: 
  604.                     keyword = token(fp); keyword = token(fp);
  605.                     keyword = token(fp); keyword = token(fp);
  606.             break;
  607.         case LIGATURE:
  608.                     keyword = token(fp); keyword = token(fp);
  609.             break;
  610.                 case NOPE:
  611.                 default: 
  612.                     error = parseError;
  613.                     break;
  614.             } /* switch */
  615.     } /* while */
  616.     
  617.     return(error);
  618.     
  619. } /* parseCharWidths */    
  620.  
  621.  
  622. /************************* parseCharMetrics ************************/
  623.  
  624. /*  This function is called by parseFile if the caller of parseFile
  625.  *  requested that all character metric information be saved
  626.  *  (as opposed to only the character width information).
  627.  *
  628.  *  parseCharMetrics is passed in a pointer to an array of records
  629.  *  to hold information on a per character basis. This function
  630.  *  parses the Character Metrics section storing all character
  631.  *  metric information for the ALL characters (mapped and unmapped) 
  632.  *  into the array.
  633.  *
  634.  *  This function returns an error code specifying whether there was 
  635.  *  a premature EOF or a parsing error. This return value is used by 
  636.  *  parseFile to determine if there is more file to parse.
  637.  */
  638.  
  639. static int parseCharMetrics(FILE *fp, FontInfo *fi)
  640. {  
  641.     BooL cont = TRUE, firstTime = TRUE;
  642.     int error = ok, count = 0;
  643.     register CharMetricInfo *temp = fi->cmi;
  644.     register char *keyword;
  645.   
  646.     while (cont)
  647.     {
  648.         keyword = token(fp);
  649.         if (keyword == NULL)
  650.         {
  651.             error = earlyEOF;
  652.             break; /* get out of loop */
  653.         }
  654.         switch(recognize(keyword))
  655.         {
  656.             case COMMENT:
  657.                 keyword = linetoken(fp);
  658.                 break; 
  659.             case CODE:
  660.                 if (count < fi->numOfChars)
  661.                 { 
  662.                     if (firstTime) firstTime = FALSE;
  663.                     else temp++;
  664.                     temp->code = atoi(token(fp));
  665.                     count++;
  666.                 }
  667.                 else
  668.                 {
  669.                     error = parseError;
  670.                     cont = FALSE;
  671.                 }
  672.                 break;
  673.             case XYWIDTH:
  674.                 temp->wx = atoi(token(fp));
  675.                 temp->wy = atoi(token(fp));
  676.                 break;                 
  677.             case XWIDTH: 
  678.                 temp->wx = atoi(token(fp));
  679.                 break;
  680.             case CHARNAME: 
  681.                 keyword = token(fp);
  682.                 temp->name = (char *) malloc(strlen(keyword) + 1);
  683.                 strcpy(temp->name, keyword);
  684.                 break;            
  685.             case CHARBBOX: 
  686. #ifdef OPTIMIZE_DONT_USE
  687.                 temp->charBBox.llx = atoi(token(fp));
  688.                 temp->charBBox.lly = atoi(token(fp));
  689.                 temp->charBBox.urx = atoi(token(fp));
  690.                 temp->charBBox.ury = atoi(token(fp));
  691. #else
  692.         (void) token(fp);
  693.         (void) token(fp);
  694.         (void) token(fp);
  695.         (void) token(fp);
  696. #endif
  697.                 break;
  698.             case LIGATURE: {
  699.                 Ligature **tail = &(temp->ligs);
  700.                 Ligature *node = *tail;
  701.                 
  702.                 if (*tail != NULL)
  703.                 {
  704.                     while (node->next != NULL)
  705.                         node = node->next;
  706.                     tail = &(node->next); 
  707.                 }
  708.                 
  709.                 *tail = (Ligature *) calloc(1, sizeof(Ligature));
  710.                 keyword = token(fp);
  711.                 (*tail)->succ = (char *) malloc(strlen(keyword) + 1);
  712.                 strcpy((*tail)->succ, keyword);
  713.                 keyword = token(fp);
  714.                 (*tail)->lig = (char *) malloc(strlen(keyword) + 1);
  715.                 strcpy((*tail)->lig, keyword);
  716.                 break; }
  717.             case ENDCHARMETRICS:
  718.                 cont = FALSE;;
  719.                 break; 
  720.             case ENDFONTMETRICS: 
  721.                 cont = FALSE;
  722.                 error = normalEOF;
  723.                 break; 
  724.             case NOPE:
  725.             default:
  726.                 error = parseError; 
  727.                 break; 
  728.         } /* switch */
  729.     } /* while */
  730.     
  731.     if ((error == ok) && (count != fi->numOfChars))
  732.         error = parseError;
  733.     
  734.     return(error);
  735.     
  736. } /* parseCharMetrics */    
  737.  
  738.  
  739.  
  740. /************************* parseTrackKernData ***********************/
  741.  
  742. /*  This function is called by "parseFile". It will parse the AFM File 
  743.  *  up to the "EndTrackKern" or "EndKernData" keywords. It will save the
  744.  *  track kerning data if requested by the caller of parseFile.
  745.  *
  746.  *  parseTrackKernData is passed in a pointer to the FontInfo record.
  747.  *  If data is to be saved, the FontInfo record will already contain 
  748.  *  a valid pointer to storage for the track kerning data.
  749.  *
  750.  *  This function returns an error code specifying whether there was 
  751.  *  a premature EOF or a parsing error. This return value is used by 
  752.  *  parseFile to determine if there is more file to parse.
  753.  */
  754.  
  755. static int parseTrackKernData(FILE *fp, FontInfo *fi)
  756. {  
  757.     BooL cont = TRUE, save = (fi->tkd != NULL);
  758.     int pos = 0, error = ok, tcount = 0;
  759.     register char *keyword;
  760.   
  761.     while (cont)
  762.     {
  763.         keyword = token(fp);
  764.         
  765.         if (keyword == NULL)
  766.         {
  767.             error = earlyEOF;
  768.             break; /* get out of loop */
  769.         }
  770.         if (!save)
  771.           /* get tokens until the end of the Track Kerning Data */
  772.           /* section without saving any of the data */
  773.             switch(recognize(keyword))
  774.             {
  775.                 case ENDTRACKKERN:
  776.                 case ENDKERNDATA:
  777.                     cont = FALSE;
  778.                     break;
  779.                 case ENDFONTMETRICS:
  780.                     cont = FALSE;
  781.                     error = normalEOF;
  782.                     break;
  783.                 default:
  784.                     break;
  785.             } /* switch */
  786.     else
  787.           /* otherwise parse entire Track Kerning Data section, */
  788.           /* saving the data */
  789.             switch(recognize(keyword))
  790.             {
  791.                 case COMMENT:
  792.                     keyword = linetoken(fp);
  793.                     break;
  794.                 case TRACKKERN:
  795.                     if (tcount < fi->numOfTracks)
  796.                     {
  797.                         keyword = token(fp);
  798.                         fi->tkd[pos].degree = atoi(keyword);
  799.                         keyword = token(fp);
  800.                         fi->tkd[pos].minPtSize = atof(keyword);
  801.                         if (errno == ERANGE) error = parseError;
  802.                         keyword = token(fp);
  803.                         fi->tkd[pos].minKernAmt = atof(keyword);
  804.                         if (errno == ERANGE) error = parseError;
  805.                         keyword = token(fp);
  806.                         fi->tkd[pos].maxPtSize = atof(keyword);
  807.                         if (errno == ERANGE) error = parseError;
  808.                         keyword = token(fp);
  809.                         fi->tkd[pos++].maxKernAmt = atof(keyword);
  810.                         if (errno == ERANGE) error = parseError;
  811.                         tcount++;
  812.                     }
  813.                     else
  814.                     {
  815.                         error = parseError;
  816.                         cont = FALSE;
  817.                     }
  818.                     break;
  819.                 case ENDTRACKKERN:
  820.                 case ENDKERNDATA:
  821.                     cont = FALSE;
  822.                     break;
  823.                 case ENDFONTMETRICS:
  824.                     cont = FALSE;
  825.                     error = normalEOF;
  826.                     break;
  827.                 case NOPE:
  828.                 default:
  829.                     error = parseError;
  830.                     break;
  831.             } /* switch */
  832.     } /* while */
  833.     
  834.     if (error == ok && tcount != fi->numOfTracks)
  835.         error = parseError;
  836.         
  837.     return(error);
  838.     
  839. } /* parseTrackKernData */    
  840.  
  841.  
  842. /************************* parsePairKernData ************************/
  843.  
  844. /*  This function is called by "parseFile". It will parse the AFM File 
  845.  *  up to the "EndKernPairs" or "EndKernData" keywords. It will save
  846.  *  the pair kerning data if requested by the caller of parseFile.
  847.  *
  848.  *  parsePairKernData is passed in a pointer to the FontInfo record.
  849.  *  If data is to be saved, the FontInfo record will already contain 
  850.  *  a valid pointer to storage for the pair kerning data.
  851.  *
  852.  *  This function returns an error code specifying whether there was 
  853.  *  a premature EOF or a parsing error. This return value is used by 
  854.  *  parseFile to determine if there is more file to parse.
  855.  */
  856.  
  857. static int parsePairKernData(FILE *fp, FontInfo *fi)
  858. {  
  859.     BooL cont = TRUE, save = (fi->pkd != NULL);
  860.     int pos = 0, error = ok, pcount = 0;
  861.     register char *keyword;
  862.   
  863.     while (cont)
  864.     {
  865.         keyword = token(fp);
  866.         
  867.         if (keyword == NULL)
  868.         {
  869.             error = earlyEOF;
  870.             break; /* get out of loop */
  871.         }
  872.         if (!save)
  873.           /* get tokens until the end of the Pair Kerning Data */
  874.           /* section without saving any of the data */
  875.             switch(recognize(keyword))
  876.             {
  877.                 case ENDKERNPAIRS:
  878.                 case ENDKERNDATA:
  879.                     cont = FALSE;
  880.                     break;
  881.                 case ENDFONTMETRICS:
  882.                     cont = FALSE;
  883.                     error = normalEOF;
  884.                     break;
  885.                 default:
  886.                     break;
  887.             } /* switch */
  888.     else
  889.           /* otherwise parse entire Pair Kerning Data section, */
  890.           /* saving the data */
  891.             switch(recognize(keyword))
  892.             {
  893.                 case COMMENT:
  894.                     keyword = linetoken(fp);
  895.                     break;
  896.                 case KERNPAIR:
  897.                     if (pcount < fi->numOfPairs)
  898.                     {
  899.                         keyword = token(fp);
  900.                         fi->pkd[pos].name1 = (char *) 
  901.                             malloc(strlen(keyword) + 1);
  902.                         strcpy(fi->pkd[pos].name1, keyword);
  903.                         keyword = token(fp);
  904.                         fi->pkd[pos].name2 = (char *) 
  905.                             malloc(strlen(keyword) + 1);
  906.                         strcpy(fi->pkd[pos].name2, keyword);
  907.                         keyword = token(fp);
  908.                         fi->pkd[pos].xamt = atoi(keyword);
  909.                         keyword = token(fp);
  910.                         fi->pkd[pos++].yamt = atoi(keyword);
  911.                         pcount++;
  912.                     }
  913.                     else
  914.                     {
  915.                         error = parseError;
  916.                         cont = FALSE;
  917.                     }
  918.                     break;
  919.                 case KERNPAIRXAMT:
  920.                     if (pcount < fi->numOfPairs)
  921.                     {
  922.                         keyword = token(fp);
  923.                         fi->pkd[pos].name1 = (char *) 
  924.                             malloc(strlen(keyword) + 1);
  925.                         strcpy(fi->pkd[pos].name1, keyword);
  926.                         keyword = token(fp);
  927.                         fi->pkd[pos].name2 = (char *) 
  928.                             malloc(strlen(keyword) + 1);
  929.                         strcpy(fi->pkd[pos].name2, keyword);
  930.                         keyword = token(fp);
  931.                         fi->pkd[pos++].xamt = atoi(keyword);
  932.                         pcount++;
  933.                     }
  934.                     else
  935.                     {
  936.                         error = parseError;
  937.                         cont = FALSE;
  938.                     }
  939.                     break;
  940.                 case ENDKERNPAIRS:
  941.                 case ENDKERNDATA:
  942.                     cont = FALSE;
  943.                     break;
  944.                 case ENDFONTMETRICS:
  945.                     cont = FALSE;
  946.                     error = normalEOF;
  947.                     break;
  948.                 case NOPE:
  949.                 default:
  950.                     error = parseError;
  951.                     break;
  952.             } /* switch */
  953.     } /* while */
  954.     
  955.     if (error == ok && pcount != fi->numOfPairs)
  956.         error = parseError;
  957.         
  958.     return(error);
  959.     
  960. } /* parsePairKernData */    
  961.  
  962.  
  963. /************************* parseCompCharData **************************/
  964.  
  965. /*  This function is called by "parseFile". It will parse the AFM File 
  966.  *  up to the "EndComposites" keyword. It will save the composite 
  967.  *  character data if requested by the caller of parseFile.
  968.  *
  969.  *  parseCompCharData is passed in a pointer to the FontInfo record, and 
  970.  *  a boolean representing if the data should be saved.
  971.  *
  972.  *  This function will create the appropriate amount of storage for
  973.  *  the composite character data and store a pointer to the storage
  974.  *  in the FontInfo record.
  975.  *
  976.  *  This function returns an error code specifying whether there was 
  977.  *  a premature EOF or a parsing error. This return value is used by 
  978.  *  parseFile to determine if there is more file to parse.
  979.  */
  980.  
  981. static int parseCompCharData(FILE *fp, FontInfo *fi)
  982. {  
  983.     BooL cont = TRUE, firstTime = TRUE, save = (fi->ccd != NULL);
  984.     int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0;
  985.     register char *keyword;
  986.   
  987.     while (cont)
  988.     {
  989.         keyword = token(fp);
  990.         if (keyword == NULL)
  991.           /* Have reached an early and unexpected EOF. */
  992.           /* Set flag and stop parsing */
  993.         {
  994.             error = earlyEOF;
  995.             break; /* get out of loop */
  996.         }
  997.         if (ccount > fi->numOfComps)
  998.         {
  999.             error = parseError;
  1000.             break; /* get out of loop */
  1001.         }
  1002.         if (!save)
  1003.           /* get tokens until the end of the Composite Character info */
  1004.           /* section without saving any of the data */
  1005.             switch(recognize(keyword))
  1006.             {
  1007.                 case ENDCOMPOSITES:
  1008.                     cont = FALSE;
  1009.                     break;
  1010.                 case ENDFONTMETRICS:
  1011.                     cont = FALSE;
  1012.                     error = normalEOF;
  1013.                     break;
  1014.                 default:
  1015.                     break;
  1016.             } /* switch */
  1017.     else
  1018.           /* otherwise parse entire Composite Character info section, */
  1019.           /* saving the data */
  1020.             switch(recognize(keyword))
  1021.             {
  1022.                 case COMMENT:
  1023.                     keyword = linetoken(fp);
  1024.                     break;
  1025.                 case COMPCHAR:
  1026.                     if (ccount < fi->numOfComps)
  1027.                     {
  1028.                         keyword = token(fp);
  1029.                         if (pcount != fi->ccd[pos].numOfPieces)
  1030.                             error = parseError;
  1031.                         pcount = 0;
  1032.                         if (firstTime) firstTime = FALSE;
  1033.                         else pos++;
  1034.                         fi->ccd[pos].ccName = (char *) 
  1035.                             malloc(strlen(keyword) + 1);
  1036.                         strcpy(fi->ccd[pos].ccName, keyword);
  1037.                         keyword = token(fp);
  1038.                         fi->ccd[pos].numOfPieces = atoi(keyword);
  1039.                         fi->ccd[pos].pieces = (Pcc *)
  1040.                             calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
  1041.                         j = 0;
  1042.                         ccount++;
  1043.                     }
  1044.                     else
  1045.                     {
  1046.                         error = parseError;
  1047.                         cont = FALSE;
  1048.                     }
  1049.                     break;
  1050.                 case COMPCHARPIECE:
  1051.                     if (pcount < fi->ccd[pos].numOfPieces)
  1052.                     {
  1053.                         keyword = token(fp);
  1054.                         fi->ccd[pos].pieces[j].pccName = (char *) 
  1055.                                 malloc(strlen(keyword) + 1);
  1056.                         strcpy(fi->ccd[pos].pieces[j].pccName, keyword);
  1057.                         keyword = token(fp);
  1058.                         fi->ccd[pos].pieces[j].deltax = atoi(keyword);
  1059.                         keyword = token(fp);
  1060.                         fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
  1061.                         pcount++;
  1062.                     }
  1063.                     else
  1064.                         error = parseError;
  1065.                     break;
  1066.                 case ENDCOMPOSITES:
  1067.                     cont = FALSE;
  1068.                     break;
  1069.                 case ENDFONTMETRICS:
  1070.                     cont = FALSE;
  1071.                     error = normalEOF;
  1072.                     break;
  1073.                 case NOPE:
  1074.                 default:
  1075.                     error = parseError;
  1076.                     break;
  1077.             } /* switch */
  1078.     } /* while */
  1079.     
  1080.     if (error == ok && ccount != fi->numOfComps)
  1081.         error = parseError;
  1082.     
  1083.     return(error);
  1084.     
  1085. } /* parseCompCharData */    
  1086.  
  1087.  
  1088.  
  1089.  
  1090. /*************************** 'PUBLIC' FUNCTION ********************/ 
  1091.  
  1092.  
  1093. /*************************** parseFile *****************************/
  1094.  
  1095. /*  parseFile is the only 'public' procedure available. It is called 
  1096.  *  from an application wishing to get information from an AFM file.
  1097.  *  The caller of this function is responsible for locating and opening
  1098.  *  an AFM file and handling all errors associated with that task.
  1099.  *
  1100.  *  parseFile expects 3 parameters: a vaild file pointer, a pointer
  1101.  *  to a (FontInfo *) variable (for which storage will be allocated and
  1102.  *  the data requested filled in), and a mask specifying which
  1103.  *  data from the AFM File should be saved in the FontInfo structure.
  1104.  *
  1105.  *  The file will be parsed and the requested data will be stored in 
  1106.  *  a record of type FontInfo (refer to ParseAFM.h).
  1107.  *
  1108.  *  parseFile returns an error code as defined in parseAFM.h. 
  1109.  *
  1110.  *  The position of the read/write pointer associated with the file 
  1111.  *  pointer upon return of this function is undefined.
  1112.  */
  1113.  
  1114. /* Thu Jun 11 19:51:41 MEST 1998
  1115.  * tm: changed name from parseFile to pdf_parseFile in
  1116.  * order to avoid name clashes with other packages
  1117.  */
  1118.  
  1119. int pdf_parseFile ( FILE *fp, FontInfo **fi, FLAGS flags) {
  1120.     
  1121.     int code = ok;     /* return code from each of the parsing routines */
  1122.     int error = ok;    /* used as the return code from this function */
  1123.     
  1124.     register char *keyword; /* used to store a token */     
  1125.     
  1126.                      
  1127.     /* storage data for the global variable ident */                  
  1128.     ident = (char *) calloc(MAX_NAME, sizeof(char)); 
  1129.     if (ident == NULL) {error = storageProblem; return(error);}      
  1130.   
  1131.     (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
  1132.     if ((*fi) == NULL) {error = storageProblem; return(error);}      
  1133.   
  1134.     if (flags & P_G) 
  1135.     {
  1136.         (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
  1137.         if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}      
  1138.     }
  1139.     
  1140.     /* The AFM File begins with Global Font Information. This section */
  1141.     /* will be parsed whether or not information should be saved. */     
  1142.     code = parseGlobals(fp, (*fi)->gfi); 
  1143.     
  1144.     if (code < 0) error = code;
  1145.     
  1146.     /* The Global Font Information is followed by the Character Metrics */
  1147.     /* section. Which procedure is used to parse this section depends on */
  1148.     /* how much information should be saved. If all of the metrics info */
  1149.     /* is wanted, parseCharMetrics is called. If only the character widths */
  1150.     /* is wanted, parseCharWidths is called. parseCharWidths will also */
  1151.     /* be called in the case that no character data is to be saved, just */
  1152.     /* to parse through the section. */
  1153.   
  1154.     if ((code != normalEOF) && (code != earlyEOF))
  1155.     {
  1156.         (*fi)->numOfChars = atoi(token(fp));
  1157.         if (flags & (P_M ^ P_W))
  1158.         {
  1159.             (*fi)->cmi = (CharMetricInfo *) 
  1160.                       calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
  1161.            if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
  1162.             code = parseCharMetrics(fp, *fi);             
  1163.         }
  1164.         else
  1165.         {
  1166.             if (flags & P_W)
  1167.             { 
  1168.                 (*fi)->cwi = (int *) calloc(256, sizeof(int)); 
  1169.                 if ((*fi)->cwi == NULL) 
  1170.                 {
  1171.                     error = storageProblem; 
  1172.                     return(error);
  1173.                 }
  1174.             }
  1175.             /* parse section regardless */
  1176.             code = parseCharWidths(fp, (*fi)->cwi);
  1177.         } /* else */
  1178.     } /* if */
  1179.     
  1180.     if ((error != earlyEOF) && (code < 0)) error = code;
  1181.     
  1182.     /* The remaining sections of the AFM are optional. This code will */
  1183.     /* look at the next keyword in the file to determine what section */
  1184.     /* is next, and then allocate the appropriate amount of storage */
  1185.     /* for the data (if the data is to be saved) and call the */
  1186.     /* appropriate parsing routine to parse the section. */
  1187.     
  1188.     while ((code != normalEOF) && (code != earlyEOF))
  1189.     {
  1190.         keyword = token(fp);
  1191.         if (keyword == NULL)
  1192.           /* Have reached an early and unexpected EOF. */
  1193.           /* Set flag and stop parsing */
  1194.         {
  1195.             code = earlyEOF;
  1196.             break; /* get out of loop */
  1197.         }
  1198.         switch(recognize(keyword))
  1199.         {
  1200.             case STARTKERNDATA:
  1201.                 break;
  1202.             case ENDKERNDATA:
  1203.                 break;
  1204.             case STARTTRACKKERN:
  1205.                 keyword = token(fp);
  1206.                 if (flags & P_T)
  1207.                 {
  1208.                     (*fi)->numOfTracks = atoi(keyword);
  1209.                     (*fi)->tkd = (TrackKernData *) 
  1210.                         calloc((*fi)->numOfTracks, sizeof(TrackKernData));
  1211.                     if ((*fi)->tkd == NULL) 
  1212.                     {
  1213.                         error = storageProblem; 
  1214.                         return(error);
  1215.                     }
  1216.                 } /* if */
  1217.                 code = parseTrackKernData(fp, *fi);
  1218.                 break;
  1219.             case STARTKERNPAIRS:
  1220.                 keyword = token(fp);
  1221.                 if (flags & P_P)
  1222.                 {
  1223.                     (*fi)->numOfPairs = atoi(keyword);
  1224.                     (*fi)->pkd = (PairKernData *) 
  1225.                         calloc((*fi)->numOfPairs, sizeof(PairKernData));
  1226.                     if ((*fi)->pkd == NULL) 
  1227.                     {
  1228.                         error = storageProblem; 
  1229.                         return(error);
  1230.                     }
  1231.                 } /* if */
  1232.                 code = parsePairKernData(fp, *fi);
  1233.                 break;
  1234.             case STARTCOMPOSITES:
  1235.                 keyword = token(fp);
  1236.                 if (flags & P_C)
  1237.                 { 
  1238.                     (*fi)->numOfComps = atoi(keyword);
  1239.                     (*fi)->ccd = (CompCharData *) 
  1240.                         calloc((*fi)->numOfComps, sizeof(CompCharData));
  1241.                     if ((*fi)->ccd == NULL) 
  1242.                     {
  1243.                         error = storageProblem; 
  1244.                         return(error);
  1245.                     }
  1246.                 } /* if */
  1247.                 code = parseCompCharData(fp, *fi); 
  1248.                 break;    
  1249.             case ENDFONTMETRICS:
  1250.                 code = normalEOF;
  1251.                 break;
  1252.             case NOPE:
  1253.             default:
  1254.                 code = parseError;
  1255.                 break;
  1256.         } /* switch */
  1257.         
  1258.         if ((error != earlyEOF) && (code < 0)) error = code;
  1259.         
  1260.     } /* while */
  1261.   
  1262.     if ((error != earlyEOF) && (code < 0)) error = code;
  1263.     
  1264. #ifdef ORIG        /* HACK */
  1265.     if (ident != NULL) { free(ident); ident = NULL; }
  1266. #endif
  1267.         
  1268.     return(error);
  1269.   
  1270. } /* parseFile */
  1271.  
  1272. /*************************** freeStorage ***********************/
  1273.  
  1274. void freeStorage(FontInfo *fi)
  1275. {
  1276.     if (fi != NULL) {
  1277.         if (fi->gfi != NULL) { 
  1278.             free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL;
  1279.             free(fi->gfi->fontName); fi->gfi->fontName = NULL;
  1280.             free(fi->gfi->fullName); fi->gfi->fullName = NULL;
  1281.             free(fi->gfi->familyName); fi->gfi->familyName = NULL;
  1282.             free(fi->gfi->weight); fi->gfi->weight = NULL;
  1283.             free(fi->gfi->version); fi->gfi->version = NULL;
  1284.             free(fi->gfi->notice); fi->gfi->notice = NULL;
  1285.             free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL;
  1286.             free(fi->gfi); fi->gfi = NULL;
  1287.         }
  1288.   
  1289.         if (fi->cwi != NULL)
  1290.         { free(fi->cwi); fi->cwi = NULL; }
  1291.  
  1292.         if (fi->cmi != NULL) { 
  1293.             int i = 0;
  1294.             CharMetricInfo *temp = fi->cmi;
  1295.             Ligature *node = temp->ligs;
  1296.             
  1297.             for (i = 0; i < fi->numOfChars; ++i)
  1298.             {
  1299.                 for (node = temp->ligs; node != NULL; node = node->next)
  1300.                 {
  1301.                     free(node->succ); node->succ = NULL;
  1302.                     free(node->lig); node->lig = NULL;
  1303.                 }
  1304.                 
  1305.                 free(temp->name); temp->name = NULL;
  1306.                 temp++;
  1307.             }
  1308.             
  1309.             free(fi->cmi); fi->cmi = NULL;
  1310.         }
  1311.  
  1312.         if (fi->tkd != NULL)
  1313.         { free(fi->tkd); fi->tkd = NULL; }
  1314.   
  1315.         if (fi->pkd != NULL) { 
  1316.             free(fi->pkd->name1); fi->pkd->name1 = NULL;
  1317.             free(fi->pkd->name2); fi->pkd->name2 = NULL;
  1318.             free(fi->pkd); fi->pkd = NULL;
  1319.         }
  1320.  
  1321.         if (fi->ccd != NULL) { 
  1322.             int i = 0, j = 0;
  1323.             CompCharData *ccd = fi->ccd;
  1324.             
  1325.             for (i = 0; i < fi->numOfComps; ++i)
  1326.             {
  1327.                 for (j = 0; j < ccd[i].numOfPieces; ++j)
  1328.                 {
  1329.                     free(ccd[i].pieces[j].pccName); 
  1330.                     ccd[i].pieces[j].pccName = NULL;
  1331.                 }
  1332.                 
  1333.                 free(ccd[i].ccName); ccd[i].ccName = NULL;
  1334.             }
  1335.     
  1336.             free(fi->ccd); fi->ccd = NULL;
  1337.         }
  1338.         
  1339.         free(fi);
  1340.  
  1341.     } /* if */ 
  1342.   
  1343. } /* freeStorage */
  1344.